package com.wyh.lotterysystem.service.impl;

import com.wyh.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import com.wyh.lotterysystem.common.exception.ServiceException;
import com.wyh.lotterysystem.common.utils.JacksonUtil;
import com.wyh.lotterysystem.common.utils.RedisUtil;
import com.wyh.lotterysystem.controller.request.*;
import com.wyh.lotterysystem.controller.response.ActivityListResponse;
import com.wyh.lotterysystem.dao.dataobject.*;
import com.wyh.lotterysystem.dao.mapper.*;
import com.wyh.lotterysystem.service.ActivityService;
import com.wyh.lotterysystem.service.PrizeService;
import com.wyh.lotterysystem.service.UserService;
import com.wyh.lotterysystem.service.dto.ActivityDetailDTO;
import com.wyh.lotterysystem.service.dto.CreateActivityDTO;
import com.wyh.lotterysystem.service.dto.PageDTO;
import com.wyh.lotterysystem.service.enums.ActivityPrizeStatusEnum;
import com.wyh.lotterysystem.service.enums.ActivityPrizeTiersEnum;
import com.wyh.lotterysystem.service.enums.ActivityStatusEnum;
import com.wyh.lotterysystem.service.enums.ActivityUserStatusEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ActivityServiceImpl implements ActivityService {
    @Resource(name = "userServiceImpl")
    UserService userService;

    @Resource(name = "prizeServiceImpl")
    PrizeService prizeService;

    @Autowired
    UserMapper userMapper;

    @Autowired
    PrizeMapper prizeMapper;

    @Autowired
    ActivityMapper activityMapper;

    @Autowired
    ActivityPrizeMapper activityPrizeMapper;

    @Autowired
    ActivityUserMapper activityUserMapper;

    @Autowired
    RedisUtil redisUtil;

    private static final String ACTIVITY_PREFIX = "activity_id";

    private static final Long ACTIVITY_TIMEOUT = 60*60*24*3L;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public CreateActivityDTO createActivity(CreateActivityRequest request) {
        //校验参数
        checkCreateActivityRequest(request);

        //保存数据

        //1.保存活动的基本信息

        //1).创建活动对象
        ActivityDo activityDo = new ActivityDo();
        activityDo.setActivityName(request.getActivityName());
        activityDo.setDescription(request.getDescription());
        activityDo.setStatus(ActivityStatusEnum.RUNNING.name());

        //2).插入数据库,并且获取id
        activityMapper.insertActivity(activityDo);

        //2.保存活动关联奖品

        //1).创建活动关联奖品对象
        List<ActivityPrizeDo> activityPrizeDos = new ArrayList<>();
        activityPrizeDos = request.getActivityPrizeList().stream().map(activityPrize->{
            ActivityPrizeDo activityPrizeDo = new ActivityPrizeDo();
            activityPrizeDo.setActivityId(activityDo.getId());
            activityPrizeDo.setPrizeId(activityPrize.getPrizeId());
            activityPrizeDo.setPrizeAmount(activityPrize.getPrizeAmount());
            activityPrizeDo.setPrizeTiers(activityPrize.getPrizeTiers());
            activityPrizeDo.setStatus(ActivityPrizeStatusEnum.INIT.name());
            return activityPrizeDo;
        }).toList();

        //2).插入数据库
        activityPrizeMapper.batchInsert(activityPrizeDos);

        //3.保存活动关联的用户信息

        //1).创建活动关联对象
        List<ActivityUserDo> activityUserDos = new ArrayList<>();
        activityUserDos = request.getActivityUserList().stream().map(activityUser -> {
            ActivityUserDo userDo = new ActivityUserDo();
            userDo.setActivityId(activityDo.getId());
            userDo.setUserId(activityUser.getUserId());
            userDo.setUserName(activityUser.getUserName());
            userDo.setStatus(ActivityUserStatusEnum.INIT.name());
            return userDo;
        }).toList();

        //2).插入数据库
        activityUserMapper.batchInsert(activityUserDos);

        //缓存活动数据 活动+奖品+用户

        //获取奖品基本信息

        List<Integer> prizeIds = request.getActivityPrizeList().stream().map(ActivityPrize::getPrizeId).toList();
        List<PrizeDo> prizeDos = prizeMapper.batchSelect(prizeIds);

        ActivityDetailDTO detailDTO = new ActivityDetailDTO();
        detailDTO = convertToActivityDetailDTO(prizeDos,activityDo,activityUserDos,activityPrizeDos);
        cacheActivity(detailDTO);

        CreateActivityDTO createActivityDTO = new CreateActivityDTO();
        createActivityDTO.setActivityId(detailDTO.getActivityId());
        return createActivityDTO;
    }

    /**
     * 获取活动列表
     * @param request
     * @return
     */
    @Override
    public PageDTO<ActivityListResponse.ActivityList> getActivityList(ActivityListRequest request) {
        List<ActivityDo> activityDos = activityMapper.selectActivity(request.getPageSize(),request.offset());

        int total = activityMapper.count();

        List<ActivityListResponse.ActivityList> activityLists = activityDos.stream()
                .map(activityDo -> {
                    ActivityListResponse.ActivityList activityList = new ActivityListResponse.ActivityList();
                    activityList.setActivityId(activityDo.getId());
                    activityList.setDescription(activityDo.getDescription());
                    activityList.setActivityName(activityDo.getActivityName());
                    activityList.setValid(activityDo.getStatus().equals(ActivityStatusEnum.RUNNING.name()));
                    return activityList;
                })
                .toList();

        return new PageDTO<>(total,activityLists);
    }

    @Override
    public ActivityDetailDTO findActivityDetail(Integer activityId) {
        if (activityId == null){
            log.warn("查询活动详细信息失败，activityId为空！");
            return null;
        }

        ActivityDetailDTO detailDTO = getActivityDetailDTOFromCache(activityId);
        if (null != getActivityDetailDTOFromCache(activityId)){
            log.info("查询活动详细信息成功！detailDTO={}",
                    JacksonUtil.writeValueAsString(detailDTO));
            return detailDTO;
        }

        //如果缓存中不存在就查表

        //活动表
        ActivityDo activityDo = activityMapper.selectActivityById(activityId);

        //获取奖品表
        List<ActivityPrizeDo> activityPrizeDos = activityPrizeMapper.selectById(activityId);

        List<Integer> prizeIds = activityPrizeDos.stream()
                .map(ActivityPrizeDo::getPrizeId)
                .toList();

        List<PrizeDo> prizeDos = prizeMapper.batchSelect(prizeIds);

        //获取用户
        List<ActivityUserDo> activityUserDos = activityUserMapper.selectById(activityId);

        detailDTO = convertToActivityDetailDTO(prizeDos, activityDo, activityUserDos, activityPrizeDos);
        return detailDTO;
    }

    /**
     * 从缓存中获取活动详情
     */
    private ActivityDetailDTO getActivityDetailDTOFromCache(Integer activityId){
        if (null == activityId){
            log.warn("获取缓存活动数据的activityId为空！");
            return null;
        }

        try {
            String s = redisUtil.getValue(ACTIVITY_PREFIX + activityId);
            if (!StringUtils.hasText(s)) {
                log.info("获取的缓存活动数据为空！key={}", ACTIVITY_PREFIX+activityId);
                return null;
            }

            return JacksonUtil.readValue(s, ActivityDetailDTO.class);
        }catch (Exception e){
            log.error("获取的缓存活动数据为空！key={}", ACTIVITY_PREFIX+activityId);
            return null;
        }
    }

    @Override
    public void cacheActivityByActivityId(Integer activityId){
        if (null == activityId) {
            log.warn("要缓存的活动id为空！");
            throw new ServiceException(ServiceErrorCodeConstants.CACHE_ACTIVITY_ID_IS_EMPTY);
        }

        // 查询表数据：活动表、关联奖品、关联人员、奖品信息表
        ActivityDo aDO = activityMapper.selectActivityById(activityId);
        if (null == aDO) {
            log.error("要缓存的活动id有误！");
            throw new ServiceException(ServiceErrorCodeConstants.CACHE_ACTIVITY_ID_ERROR);
        }
        // 活动奖品表
        List<ActivityPrizeDo> apDOList =  activityPrizeMapper.selectById(activityId);
        // 活动人员表
        List<ActivityUserDo> auDOList = activityUserMapper.selectById(activityId);
        // 奖品表: 先获取要查询的奖品id
        List<Integer> prizeIds = apDOList.stream()
                .map(ActivityPrizeDo::getPrizeId)
                .toList();
        List<PrizeDo> pDOList = prizeMapper.batchSelect(prizeIds);
        // 整合活动详细信息，存放redis
        cacheActivity(
                convertToActivityDetailDTO(pDOList,aDO,auDOList, apDOList));
    }

    /**
     * 缓存活动信息
     * @param detailDTO 活动详情
     */
    private void cacheActivity(ActivityDetailDTO detailDTO) {
        if (detailDTO == null || detailDTO.getActivityId() == null){
            log.warn("要缓存的数据为空");
            return;
        }

        try {
            redisUtil.setRedisAndTime(ACTIVITY_PREFIX+detailDTO.getActivityId(),
                    JacksonUtil.writeValueAsString(detailDTO),ACTIVITY_TIMEOUT);
        }catch (Exception e) {
            log.warn("活动信息缓存失败, detailDTO：{}",JacksonUtil.writeValueAsString(detailDTO));
        }
    }

    private ActivityDetailDTO convertToActivityDetailDTO(List<PrizeDo> prizeDos,
                                                         ActivityDo activityDo,
                                                         List<ActivityUserDo> activityUserDos,
                                                         List<ActivityPrizeDo> activityPrizeDos) {
        ActivityDetailDTO detailDTO = new ActivityDetailDTO();

        //构造返回值

        //1.活动信息
        detailDTO.setActivityName(activityDo.getActivityName());
        detailDTO.setDesc(activityDo.getDescription());
        detailDTO.setStatus(ActivityStatusEnum.forName(activityDo.getStatus()));
        detailDTO.setActivityId(activityDo.getId());

        //2.奖品信息
        List<ActivityDetailDTO.PrizeDTO> prizeDTOS = activityPrizeDos.stream().map(activityPrizeDo -> {
            ActivityDetailDTO.PrizeDTO prizeDTO = new ActivityDetailDTO.PrizeDTO();

            prizeDTO.setPrizeId(activityPrizeDo.getPrizeId());
            Optional<PrizeDo> first = prizeDos.stream().filter(prizeDo -> prizeDo.getId()
                    .equals(activityPrizeDo.getPrizeId())).findFirst();
            first.ifPresent(prizeDo -> {
                prizeDTO.setName(prizeDo.getName());
                prizeDTO.setPrice(prizeDo.getPrice());
                prizeDTO.setDescription(prizeDo.getDescription());
                prizeDTO.setImageUrl(prizeDo.getImageUrl());
            });
            prizeDTO.setPrizeTierName(ActivityPrizeTiersEnum.forName(activityPrizeDo.getPrizeTiers()));
            prizeDTO.setPrizeAmount(activityPrizeDo.getPrizeAmount());
            prizeDTO.setStatus(ActivityPrizeStatusEnum.forName(activityPrizeDo.getStatus()));
            return prizeDTO;
        }).toList();
        detailDTO.setPrizeDTOList(prizeDTOS);

        //用户信息
        List<ActivityDetailDTO.UserDTO> userDTOS = activityUserDos.stream().map(activityUserDo -> {
            ActivityDetailDTO.UserDTO userDTO = new ActivityDetailDTO.UserDTO();
            userDTO.setUserName(activityUserDo.getUserName());
            userDTO.setUserId(activityUserDo.getUserId());
            userDTO.setStatus(ActivityUserStatusEnum.forName(activityUserDo.getStatus()));
            return userDTO;
        }).toList();
        detailDTO.setUserDTOList(userDTOS);

        return detailDTO;
    }

    private void checkCreateActivityRequest(CreateActivityRequest request) {
        if (null == request){
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_CREATE_ERROR);
        }

        //校验圈选人员是否都存在
        List<Integer> userIds = request.getActivityUserList().stream()
                .map(ActivityUser::getUserId)
                .distinct().toList();
        List<Integer> userDos = userMapper.getUsers(userIds);
        if (userDos.isEmpty()){
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_USER_ERROR);
        }
        userIds.forEach(id->{
            if (!userDos.contains(id)){
                throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_USER_ERROR);
            }
        });

        //校验奖品是否存在
        List<Integer> prizeIds = request.getActivityPrizeList().stream()
                .map(ActivityPrize::getPrizeId)
                .distinct().toList();
        List<Integer> prizeDos = prizeMapper.getPrizes(prizeIds);
        if (prizeDos.isEmpty()){
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_ERROR);
        }
        prizeIds.forEach(id->{
            if (!prizeDos.contains(id)){
                throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_ERROR);
            }
        });

        //人员数量大于等于奖品数
        if (prizeIds.size() > userIds.size()){
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_COUNT_ERROR);
        }

        //校验奖品的有效性
        request.getActivityPrizeList().forEach(prize->{
            if (null == ActivityPrizeTiersEnum.forName(prize.getPrizeTiers())){
                throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_TIER_ERROR);
            }
        });
    }


}
